package com.ovopark.organize.server.aop;


import com.google.common.base.Splitter;
import com.ovopark.organize.server.common.constant.ConfigurationConstants;
import com.ovopark.organize.server.common.exception.CommonException;
import com.ovopark.organize.server.common.exception.ExceptionEnum;
import com.ovopark.organize.server.common.support.LocalStorageUtils;
import com.ovopark.organize.server.common.support.StorageInfo;
import com.ovopark.organize.server.model.entity.Users;
import com.ovopark.organize.server.model.thirdpart.TokenValue;
import com.ovopark.organize.server.service.UserService;
import com.ovopark.organize.server.service.impl.thirdparty.OvoSsoServiceImpl;
import com.ovopark.organize.server.util.IpUtils;
import com.ovopark.organize.server.util.TokenUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName RequestAspect
 * @Description //
 * @Author yuyinghua@ovopark.com
 * @Date 2019/6/27 20:00
 * @Version 1.0
 **/
@Component
@Aspect
@Order(1)
@Slf4j
public class RequestAspect {

    Logger logger = LoggerFactory.getLogger(RequestAspect.class);

    private static final String GET = "GET";
    private static final String PUT = "PUT";
    private static final String POST = "POST";
    private static final String DELETE = "DELETE";
    private static final String TICKET = "ticket";
    private static final String OVOPARK_TOKEN = "authenticator";
    private static final String NEW_OVOPARK_TOKEN = "Ovo-Authorization";

    @Value("${server.servlet.context-path}")
    private String contextPath;

    @Autowired
    ConfigurationConstants configurationConstants;

    @Resource
    private UserService userService;

    @Resource
    private OvoSsoServiceImpl ovoSsoService;

    @Pointcut("execution(* com.ovopark.organize.server.controller.*Controller.*(..))")
    public void allControllerRequestCut() {
    }

    //   @Pointcut("execution(* com.ovopark.organize.server.controller..*(..))")
    //   @Pointcut("execution(* com.ovopark.organize.server.controller.*Controller.*(..))")

    
    @Around("allControllerRequestCut()")
    public Object allControllerRequestBeforePoint(ProceedingJoinPoint pjp) throws Throwable {

        LocalStorageUtils.remove();
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        MDC.clear();
        // 从上层调用继承过来
        String requestId = request.getHeader("requestId");
        if (org.apache.commons.lang3.StringUtils.isEmpty(requestId)) {
            // 假如上层没传过来，自己生成
            requestId = UUID.randomUUID().toString();
        }
        MDC.put("requestId", requestId);
        String remoteIp = IpUtils.getRemoteIp(request);
        StorageInfo storageInfo = LocalStorageUtils.getStorageInfo();
        storageInfo.setRemoteIp(remoteIp);
        String platform = getPlatform(request);
        LocalStorageUtils.getStorageInfo().setUserPlatform(platform);
        checkToken(request);

        Object result = null;
        result = pjp.proceed();



       /* try {
            if (pjp.getArgs().length > 0) {
                StringBuilder sb = new StringBuilder();
                for (Object o : pjp.getArgs()) {
                    if (o instanceof MultipartFile){
                        MultipartFile file = (MultipartFile) o;
                        continue;
                    }else if (o instanceof MultipartFile[]){
                        MultipartFile[] files = (MultipartFile[]) o;
                        continue;
                    }else {
                 *//*       log.info("接口：{}，请求参数 : {}",String.format("%s.%s", pjp.getSignature().getDeclaringTypeName(), pjp.getSignature().getName())
                                , JSON.toJSONString(o));*//*
                        sb.append(JSON.toJSONString(o)).append(",");
                    }
                    if (o instanceof HttpServletRequest || o instanceof HttpServletResponse) {
                        continue;
                    }

                }

                log.info("接口：{}， requestId :{},请求参数 : {}",String.format("%s.%s", pjp.getSignature().getDeclaringTypeName(), pjp.getSignature().getName()),requestId
                        , sb.toString());
            }
        }catch (Exception e){

        }*/




        return result;
    }


    private void checkToken(HttpServletRequest request) {
        String requestURI = request.getMethod() + request.getRequestURI().replace(contextPath, "");
        try {
            request.setCharacterEncoding("UTF-8");
        }catch (Exception e){
            logger.info("转义错误："+requestURI);
        }


//        List<String> list = noCheckUri.stream().filter(requestURI::contains).collect(Collectors.toList());

     //  logger.info("requestURI===="+requestURI+" param====" +JSONObject.toJSONString(request.getParameterMap()) + "_____"+JSONObject.toJSONString(request.getParameterMap()));

        List<String> whiteList = configurationConstants.getWhiteList();

        //白名单判断走配置文件处理
        List<String> list = whiteList.stream().filter(requestURI::contains).collect(Collectors.toList());

        String newOvoToken = request.getHeader(NEW_OVOPARK_TOKEN);
        if(requestURI.contains("enterprise/getCategoryTree") && StringUtils.isNotEmpty(newOvoToken)){
            // 企业分类树 如果能取到 token 则校验

        }else  if (!CollectionUtils.isEmpty(list)) {
            return;
        }

        Integer userId = null;
        Users users = null;
        String ovoToken = null;
        if (!StringUtils.isEmpty(newOvoToken)){
            ovoToken = newOvoToken;
            //  TokenValue tokenValue = parseNewToken(newOvoToken);
            com.ovopark.sso.model.TokenValue tokenValue = parseTokenBySdk(newOvoToken);
            if (tokenValue == null){
                throw new CommonException(ExceptionEnum.INVALID_TOKEN);
            }
            StorageInfo mo = LocalStorageUtils.getStorageInfo();
            setStorageInfo(ovoToken, mo);
            mo.setUserId(tokenValue.getUserId());
            mo.setGroupId(tokenValue.getGroupId());
            mo.setUserName(tokenValue.getUserName());
            mo.setIsAgency(tokenValue.getIsAgency());
            mo.setIsAccountUser(tokenValue.getIsAccountUser());
            LocalStorageUtils.setStorageInfo(mo);
        }else {
            ovoToken = request.getHeader(OVOPARK_TOKEN);

            if (!StringUtils.isEmpty(ovoToken)){
                String userIdStr = TokenUtils.getUserId(ovoToken);
                if (StringUtils.isEmpty(userIdStr)){
                    throw new CommonException(ExceptionEnum.INVALID_TOKEN);
                }
                userId = Integer.valueOf(userIdStr);
            }else{
                ovoToken = request.getParameter(TICKET);
                if (!StringUtils.isEmpty(ovoToken)){
                    userId = parseNewTickeToken(ovoToken);
                    if (userId ==null){
                        throw new CommonException(ExceptionEnum.INVALID_TOKEN);
                    }
                }
            }
            if (userId!=null){
                users = this.userService.getUsersById(userId);
                if (users!=null){
                    StorageInfo mo = LocalStorageUtils.getStorageInfo();
                    ovoToken = setStorageInfo(ovoToken, mo);
                    mo.setUserId(users.getId());
                    mo.setGroupId(users.getGroupId());
                    mo.setUserName(users.getUserName());
                    mo.setIsAgency(users.getIsAgency());
                    mo.setIsAccountUser(0);
                    LocalStorageUtils.setStorageInfo(mo);
                }
            } else {
                throw new CommonException(ExceptionEnum.INVALID_TOKEN);
            }
        }


       /* StorageInfo mo = LocalStorageUtils.getStorageInfo();
        if(mo !=null){
            logger.info("checkToken userId:"+ mo.getUserId() +" groupId:"+mo.getGroupId()+"  userName:"+mo.getUserName() +"isAgency："+mo.getIsAgency());
        }*/
      /*  if(users !=null){
            logger.info("requestURI:"+requestURI+" groupId:"+users.getGroupId()+" userId:"+users.getId()+"  userName:"+users.getUserName());
        }*/

    }


    /**
     * 解析新token
     * @param newOvoToken
     * @return
     */
    private TokenValue parseNewToken(String newOvoToken){
        List<String> list= Splitter.on(" ").splitToList(newOvoToken);
        if(list.size()>0){
            newOvoToken = list.get(0);
        }
        return ovoSsoService.parseToken(newOvoToken);
    }

    private com.ovopark.sso.model.TokenValue parseTokenBySdk(String newOvoToken){
        List<String> list= Splitter.on(" ").splitToList(newOvoToken);
        if(list.size()>0){
            newOvoToken = list.get(0);
        }
        return ovoSsoService.parseNewToken(newOvoToken);
    }


    /**
     * 解析新token
     * @param newOvoToken
     * @return
     */
    private Integer parseNewTickeToken(String newOvoToken){
        return ovoSsoService.parseNewToken(newOvoToken).getUserId();
    }


    private String setStorageInfo(String ovoToken, StorageInfo mo) {
        // token client version lang timezone deviceName deviceSerialNo
        String[] auths = ovoToken.split(" ");
        if (auths.length > 0 && StringUtils.isNotEmpty(ovoToken)) {
            ovoToken = auths[0];
            mo.setToken(ovoToken);
        }
        if (auths.length > 1) {
            mo.setClient(auths[1]);
        }
        if (auths.length > 2) {
            mo.setVersion(auths[2]);
        }
        if (auths.length > 3) {
            mo.setLang(auths[3]);
            if ("ENGLISH".equalsIgnoreCase(auths[3])) {//英文
                mo.setLocale(Locale.US);
            } else if ("TRADITIONAL_CHINESE".equalsIgnoreCase(auths[3])) {//繁体中文
                mo.setLocale(Locale.TRADITIONAL_CHINESE);
            } if ("INDONESIA".equalsIgnoreCase(auths[3])) {//印尼
                mo.setLocale(new Locale("in", "ID"));
            }
        }
        if (auths.length > 4) {
            try {
                mo.setTimeZone(TimeZone.getTimeZone(auths[4]));
            } catch(Exception e) {
                log.info("--------------TimeZone translate faied, timeZone:" + auths[4]);
            }
        }
        if (auths.length > 5) {
            mo.setDeviceName(auths[5]);
        }
        if (auths.length > 6) {
            mo.setDeviceSerialNo(auths[6]);
        }
        mo.setToken(ovoToken);
        return ovoToken;
    }




    /**
     * 不需要权限过滤的路径 放入配置文件了
     */
//    private static final List<String> noCheckUri = Lists.newArrayList(
//            "/test/",
//            "/common/",
//            "deviceBlackList",
//            "/fr3Pro/",
//            "/rentRule/getShopNextRentDate",
//            "/rentRule/getShopNextWarningRentDate"
//    );


    public static String getPlatform(HttpServletRequest request) {
        String userAgent = request.getHeader("User-Agent");
//		System.out.println("UA:===========" + userAgent);
        String platform = null;
        if (userAgent != null) {
            // 安卓使用okhttp框架
            if (userAgent.contains("Android") || userAgent.contains("okhttp")) {
                platform = "Android";
            } else if (userAgent.contains("iOS")) {
                platform = "iOS";
            } else {
                // 获取客户端浏览器
                platform = "web";
				/*StringTokenizer st = new StringTokenizer(userAgent, ";");
				st.nextToken();
				platform = st.nextToken();*/
            }
        } else {
            // TODO 没有默认UA，是自定义客户端传来的，需定义各个客户端的标记
            platform = "unknown";
        }
        return platform;
    }
}
